package com.tcoiss.webservice.apiServer.xstream.mapper;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.StringUtils;


public class MapperContextBuilder {

	public MapperContext build(String xml) {
		try {
			return buildImpl(xml);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	protected MapperContext buildImpl(String xml) throws DocumentException,
		IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		MapperContext ctx = new MapperContext();
		InputStream in = null;
		try {
			if (!StringUtils.hasLength(xml)) {
				return ctx;
			}
			SAXReader saxReader = new SAXReader();
			in = new ByteArrayInputStream(xml.getBytes());
			Document doc = saxReader.read(in);
			List children = doc.getRootElement().elements();
			for (int i = 0; i < children.size(); i++) {
				Element child=(Element) children.get(i);
//			}
//			for (Element child : children) {
				String name = child.getName();
				String methodName = "process" + name;
				try {
					Method method = this.getClass().getDeclaredMethod(methodName,
						new Class[]{Element.class, MapperContext.class});
					method.invoke(this, new Object[]{child, ctx});
				} catch (NoSuchMethodException e) {
					throw new RuntimeException("XSrteam���ô���,û�и�������!", e);
				}
			}
			return ctx;
		} catch (SecurityException e) {
			throw e;
		} finally {
			try {
				if (in != null)
					in.close();
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}			
			
		}
	}
	/*public static void main(String[] args) {
		System.out.println(Boolean.getBoolean("false"));
	}*/
	protected void processUseGlobalImplicitCollection(Element child, MapperContext ctx) {
		String value = (noNull(child, "value"));
		ctx.useGlobalImplicitCollection(Boolean.getBoolean(value));
	}
	protected void processRootType(Element child, MapperContext ctx) {
		String clz = null;
		try {
			clz = noNull(child, "value");
			ctx.setRootType(Class.forName(clz));
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("XSrteam���ô���,ָ�����಻����!" + clz);
		}
	}
	               
	protected void processAddImplicitCollection(Element child, MapperContext ctx) {
		String itemTypeStr = nullable(child, "itemType");
		String ownerTypeStr = noNull(child, "ownerType");
		Class itemType, ownerType;
		try {
			itemType = !StringUtils.hasLength(itemTypeStr) ? Object.class : Class
				.forName(itemTypeStr);
			ownerType = Class.forName(ownerTypeStr);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("XSrteam���ô���,ָ�����಻����!" + e.getMessage());
		}
		String fieldName = noNull(child, "fieldName");
		String itemName = noNull(child, "itemName");
		ctx.addImplicitCollection(ownerType, fieldName, itemName, itemType);
	}
	protected void processRootNodeName(Element child, MapperContext ctx) {
		ctx.setRootNodeName(noNull(child, "value"));
	}
	protected void processXpathToCollection(Element child, MapperContext ctx) {
		ctx.xpathToCollection(noNull(child, "xpath"), noNull(child, "nodeName"),
			nullable(child, "itemType"));
	}
	protected void processXpathImplicitCollection(Element child, MapperContext ctx) {
		ctx.addXpathImplicitCollection(noNull(child, "xpath"), noNull(child, "nodeName"),
			noNull(child, "fieldName"), nullable(child, "itemType"));
	}
	//
	private String nullable(Element child, String key) {
		Attribute attr = child.attribute(key);
		String value;
		if (attr != null) {
			value = attr.getText();
		} else
			value = child.getText();
		return value;
	}
	private String noNull(Element child, String key) {
		String value = nullable(child, key);
		if (!StringUtils.hasLength(value))
			throw new RuntimeException("XSteam���ô���,Ԫ��{" + child.getName() + "}������{" +
				key + "}ֵ����Ϊ��!");
		return value;
	}
}
